package scatter.order.rest.service.impl;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import scatter.common.rest.exception.BusinessException;
import scatter.common.rest.validation.DictService;
import scatter.dict.pojo.po.Dict;
import scatter.dict.rest.service.IDictService;
import scatter.order.pojo.constant.OrderConstants;
import scatter.order.pojo.param.RefundOrderParam;
import scatter.order.pojo.po.Order;
import scatter.order.pojo.po.OrderGoods;
import scatter.order.pojo.po.OrderRefund;
import scatter.order.pojo.po.OrderRefundGoods;
import scatter.order.rest.service.IOrderGoodsService;
import scatter.order.rest.service.IOrderRefundGoodsService;
import scatter.order.rest.service.IOrderRefundService;
import scatter.order.rest.service.IOrderService;

import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 默认的订单退款服务实现
 * </p>
 *
 * @author yangwei
 * @since 2021-07-05 04:51
 */
@Slf4j
public class DefaultRefundOrderFrameworkServiceImpl extends AbstractRefundOrderFrameworkServiceImpl<RefundOrderParam> {

	@Autowired
	private IOrderService iOrderService;
	@Autowired
	protected DictService dictService;
	@Autowired
	protected IDictService iDictService;
	@Autowired
	protected IOrderRefundService iOrderRefundService;
	@Autowired
	protected IOrderGoodsService iOrderGoodsService;

	@Autowired
	private IOrderRefundGoodsService iOrderRefundGoodsService;

	@Override
	protected boolean preRefund(RefundOrderParam param) {
		// 检查订单是否存在

		Order byOrderNo = iOrderService.getByOrderNo(param.getOrderNo());
		Assert.notNull(byOrderNo,"订单号不存在");


		Dict dictStatus = iDictService.getById(byOrderNo.getStatusDictId());
		boolean canRefund = OrderConstants.OrderStatusItem.paid.itemValue().equals(dictStatus.getValue())
				|| OrderConstants.OrderStatusItem.refunding_part_goods.itemValue().equals(dictStatus.getValue())
				|| OrderConstants.OrderStatusItem.refund_part_goods.itemValue().equals(dictStatus.getValue());
		if (!canRefund) {
			throw new BusinessException("当前订单状态（"+dictStatus.getName()+"）不能退款");
		}
		// 检查商品信息状态,是否存在已经退款或退款中的
		if (!isEmpty(param.getGoodsIds())) {
			List<OrderGoods> byGoodsIdsAndOrderId = iOrderGoodsService.getByGoodsIdsAndOrderId(param.getGoodsIds(), byOrderNo.getId());
			if (isEmpty(byGoodsIdsAndOrderId)) {
				throw new BusinessException("商品不存在");
			}
			String refundDictId = dictService.getIdByGroupCodeAndValue(OrderConstants.OrderStatusGroupCode.order_status.groupCode(), OrderConstants.OrderStatusItem.refund.itemValue());
			String refundingDictId = dictService.getIdByGroupCodeAndValue(OrderConstants.OrderStatusGroupCode.order_status.groupCode(), OrderConstants.OrderStatusItem.refunding.itemValue());
			for (OrderGoods goods : byGoodsIdsAndOrderId) {
				if (isEqual(goods.getStatusDictId(),refundDictId)) {
					throw new BusinessException(StrUtil.format("商品 {} 已退款，请不要重复退款",goods.getGoodsName()));
				}else if (isEqual(goods.getStatusDictId(),refundingDictId)) {
					throw new BusinessException(StrUtil.format("商品 {} 已在退款中，请不要重复退款",goods.getGoodsName()));
				}
			}
		}

		return super.preRefund(param);
	}

	@Override
	protected boolean doRefund(RefundOrderParam param) {

		// 将订单状态改为已退款
		Order byOrderNo = iOrderService.getByOrderNo(param.getOrderNo());
		// 设置支付类型，现付，预付等
		String orderPayType = dictService.getValueById(byOrderNo.getPayTypeDictId());
		// 是否为线下支付
		boolean isOffLinePay = isEqual(orderPayType, OrderConstants.OrderPayTypeDictItem.off_line_pay.itemValue());
		// 退款中 字典id
		String refundingStatusDictId = dictService.getIdByGroupCodeAndValue(OrderConstants.OrderStatusGroupCode.order_status.groupCode(), OrderConstants.OrderStatusItem.refunding.itemValue());

		// 已退款字典id
		String refundStatusDictId = dictService.getIdByGroupCodeAndValue(OrderConstants.OrderStatusGroupCode.order_status.groupCode(), OrderConstants.OrderStatusItem.refund.itemValue());

		List<OrderGoods> refundOrderGoods = null;

		// 是否分多次退单
		boolean isMultiple = false;
		if (isEmpty(param.getGoodsIds())) {
			refundOrderGoods = iOrderGoodsService.getByOrderId(byOrderNo.getId());
		}else {
			refundOrderGoods = iOrderGoodsService.getByGoodsIdsAndOrderId(param.getGoodsIds(), byOrderNo.getId());
		}
		// 判断传入的商品id是否是全部商品
		List<OrderGoods> allOrderGoods = iOrderGoodsService.getByOrderId(byOrderNo.getId());
		List<String> allOrderGoodsIds = allOrderGoods.stream().map(OrderGoods::getGoodsId).collect(Collectors.toList());
		List<String> refundGoodsIds = refundOrderGoods.stream().map(OrderGoods::getGoodsId).collect(Collectors.toList());
		boolean isAllContent = true;
		for (OrderGoods allOrderGood : allOrderGoods) {
			if (!refundGoodsIds.contains(allOrderGood.getGoodsId())) {
				isAllContent = false;
				break;
			}
		}
		isMultiple = !isAllContent;

		// 更新商品状态
		// 线下支付直接设置为已退款
		if (isOffLinePay) {
			refundOrderGoods.stream().forEach(g -> g.setStatusDictId(refundStatusDictId));
		}else {
			// 设置为退款中，等待回调再更新为已退款
			refundOrderGoods.stream().forEach(g -> g.setStatusDictId(refundingStatusDictId));
		}
		boolean b1 = iOrderGoodsService.updateBatchById(refundOrderGoods);
		if (!b1) {
			throw new BusinessException("退款失败，在更新商品信息状态时返回失败");
		}

		String orderStatusDictId = isOffLinePay ? refundStatusDictId : refundingStatusDictId;
		if (isOffLinePay) {
			byOrderNo.setStatusDictId(refundStatusDictId);
		}else {
			// 线上支付订单状态根据商品状态计算
			String computedOrderStatusDictId = iOrderService.computeOrderStatusByGoodsStatus(byOrderNo.getId());
			if (isStrEmpty(computedOrderStatusDictId)) {
				log.warn("退款根据商品状态计算订单状态返回为空直接设置订单状态为退款中");
				byOrderNo.setStatusDictId(refundingStatusDictId);
			}else {
				byOrderNo.setStatusDictId(computedOrderStatusDictId);
			}
		}


		// 更新订状态
		boolean b = iOrderService.updateById(byOrderNo);
		if (!b) {
			throw new BusinessException("退款失败，在更新订单退款状态时返回失败");
		}


		// 添加退款单
		OrderRefund orderRefund = new OrderRefund();
		String categoryDictId = dictService.getValueById(byOrderNo.getCategoryDictId());
		String orderRefundNO = iOrderRefundService.generateOrderRefundNO(categoryDictId);


		orderRefund.setRefundNo(orderRefundNO);
		orderRefund.setOrderNo(byOrderNo.getOrderNo());
		orderRefund.setOrderId(byOrderNo.getId());
		orderRefund.setDescription(param.getRemark());
		// 线下退款直接设置为已退款，否则为退款中，待退款后再更新状态
		orderRefund.setStatusDictId(isOffLinePay ? refundStatusDictId : refundingStatusDictId);

		Integer refundAmount = param.getAmount();
		// 未指定退款金额
		if (param.getAmount() == null) {
			// 如果不是多次，取订单总金额
			if (!isMultiple) {
				refundAmount  = byOrderNo.getTotalAmount();
			}else {
				if (!isEmpty(refundOrderGoods)) {
					refundAmount = refundOrderGoods.stream().mapToInt(OrderGoods::getAmount).sum();
				}else {
					refundAmount  = byOrderNo.getTotalAmount();
				}
			}
		}
		orderRefund.setAmount(refundAmount);
		// 是否分多笔退单
		orderRefund.setIsMultiple(isMultiple);
		orderRefund.setCurrencyDictId(byOrderNo.getCurrencyDictId());
		orderRefund.setClientIp(param.getClientIp());

		boolean orderRefundResult = iOrderRefundService.save(orderRefund);
		if (!orderRefundResult) {
			throw new BusinessException("退款失败，在保存退款单时返回失败");
		}

		// 添加退款商品，如果退款商品不为空，保存退款的商品信息
		List<OrderRefundGoods> orderRefundGoods = null;
		if (!isEmpty(refundOrderGoods)) {
			orderRefundGoods = refundOrderGoods.stream().map(orderGoods ->
					new OrderRefundGoods()
							.setOrderId(byOrderNo.getId())
							.setOrderNo(byOrderNo.getOrderNo())
							.setOrderRefundNo(orderRefund.getRefundNo())
							.setGoodsId(orderGoods.getGoodsId())
							.setOrderRefundId(orderRefund.getId())
			).collect(Collectors.toList());

		}
		if (orderRefundGoods != null) {
			boolean b2 = iOrderRefundGoodsService.saveBatch(orderRefundGoods);
			if (!b2) {
				throw new BusinessException("退款失败，在保存退款单商品时返回失败");
			}
		}

		// 其它三方支持
		thirdOtherOrder(param,byOrderNo,orderRefund);
		return true;
	}

	/**
	 * 其它第三方内部支付
	 * @param
	 * @param param
	 * @param orderRefund 退款单
	 */
	protected void thirdOtherOrder(RefundOrderParam param,Order order,OrderRefund orderRefund){

	}

	@Override
	public boolean support(String channel, String CategoryDictValue) {
		return false;
	}
}
